/**
 * Copyright 2015 bingoogolapple
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.bingoogolapple.badgeview;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

/**
 * BGABadgeViewHelper
 *
 * @since 2021-04-21
 */
public class BGABadgeViewHelper {

    private PixelMap mBitmap;
    /**
     * BGABadgeable
     */
    public BGABadgeable mBadgeable;
    private Paint mBadgePaint;
    /**
     * 徽章背景色
     */
    private int mBadgeBgColor;
    /**
     * 徽章文本的颜色
     */
    private int mBadgeTextColor;
    /**
     * 徽章文本字体大小
     */
    private int mBadgeTextSize;
    /**
     * 徽章背景与宿主控件上下边缘间距离
     */
    private int mBadgeVerticalMargin;
    /**
     * 徽章背景与宿主控件左右边缘间距离
     */
    private int mBadgeHorizontalMargin;
    /***
     * 徽章文本边缘与徽章背景边缘间的距离
     */
    private int mBadgePadding;
    /**
     * 徽章文本
     */
    private String mBadgeText;
    /**
     * 徽章文本所占区域大小
     */
    private Rect mBadgeNumberRect;
    /**
     * 是否显示Badge
     */
    private boolean mIsShowBadge;
    /**
     * 徽章在宿主控件中的位置
     */
    private BadgeGravity mBadgeGravity;
    /**
     * 整个徽章所占区域
     */
    private RectFloat mBadgeRectF;
    /**
     * 是否可拖动
     */
    private boolean mDraggable = false;
    /**
     * 拖拽徽章超出轨迹范围后，再次放回到轨迹范围时，是否恢复轨迹
     */
    private boolean mIsResumeTravel;
    /***
     * 徽章描边宽度
     */
    private int mBadgeBorderWidth;
    /***
     * 徽章描边颜色
     */
    private int mBadgeBorderColor;
    /**
     * 触发开始拖拽徽章事件的扩展触摸距离
     */
    private int mDragExtra;
    /**
     * 整个徽章加上其触发开始拖拽区域所占区域
     */
    private RectFloat mBadgeDragExtraRectF;
    /**
     * 拖动时的徽章控件
     */
    private BGADragBadgeView mDropBadgeView;
    /**
     * 是否正在拖动
     */
    private boolean mIsDragging;
    /**
     * 拖动大于BGABadgeViewHelper.mMoveHiddenThreshold后抬起手指徽章消失的代理
     */
    private BGADragDismissDelegate mDelegate;
    private boolean mIsShowDrawable = false;
    private Component topComponent;

    // Y坐标偏移高度
    private int TOPTITLEHEIGHT = 0;

    /**
     * BGABadgeViewHelper
     *
     * @param badgeable           BGABadgeable
     * @param context             Context
     * @param attrs               AttrSet
     * @param defaultBadgeGravity BadgeGravity
     */
    public BGABadgeViewHelper(BGABadgeable badgeable, Context context, AttrSet attrs, BadgeGravity defaultBadgeGravity) {
        mBadgeable = badgeable;
        initDefaultAttrs(context, defaultBadgeGravity);
        initCustomAttrs(context, attrs);
        afterInitDefaultAndCustomAttrs();
        mDropBadgeView = new BGADragBadgeView(context, this);
    }

    /**
     * initDefaultAttrs
     *
     * @param context             Context
     * @param defaultBadgeGravity BadgeGravity
     */
    private void initDefaultAttrs(Context context, BadgeGravity defaultBadgeGravity) {
        mBadgeNumberRect = new Rect();
        mBadgeRectF = new RectFloat();
        mBadgeBgColor = Color.getIntColor("#d71345");
        mBadgeTextColor = Color.getIntColor("#ffffff");
        mBadgeTextSize = BGABadgeViewUtil.sp2px(context, 10);

        mBadgePaint = new Paint();
        mBadgePaint.setAntiAlias(true);
        mBadgePaint.setStyle(Paint.Style.FILL_STYLE);

        // 设置mBadgeText居中，保证mBadgeText长度为1时，文本也能居中
        mBadgePaint.setTextAlign(TextAlignment.CENTER);

        mBadgePadding = BGABadgeViewUtil.dp2px(context, 4);
        mBadgeVerticalMargin = BGABadgeViewUtil.dp2px(context, 4);
        mBadgeHorizontalMargin = BGABadgeViewUtil.dp2px(context, 4);

        mBadgeGravity = defaultBadgeGravity;
        mIsShowBadge = false;

        mBadgeText = null;

        mBitmap = null;

        mIsDragging = false;

        mBadgeBorderColor = Color.getIntColor("#ffffff");

        mDragExtra = BGABadgeViewUtil.dp2px(context, 4);
        mBadgeDragExtraRectF = new RectFloat();
    }

    /**
     * 初始化自定义属性
     *
     * @param context Context
     * @param attrs   AttrSet
     */
    private void initCustomAttrs(Context context, AttrSet attrs) {
        initCustomAttr(attrs);
    }

    /**
     * 获取自定义属性
     *
     * @param attr AttrSet
     */
    private void initCustomAttr(AttrSet attr) {
        // 徽章背景颜色
        mBadgeBgColor = AttrUtil.getColorInteger(attr, "badge_bgColor", "#d71345");

        // 徽章文本颜色
        mBadgeTextColor = AttrUtil.getColorInteger(attr, "badge_textColor", "#ffffff");

        // 徽章文字大小
        mBadgeTextSize = AttrUtil.getDimension(attr, "badge_textSize", mBadgeTextSize);

        // 徽章背景与宿主控件上下边缘间距离
        mBadgeVerticalMargin = AttrUtil.getDimension(attr, "badge_verticalMargin", mBadgeVerticalMargin);

        // 徽章背景与宿主控件左右边缘间距离
        mBadgeHorizontalMargin = AttrUtil.getDimension(attr, "badge_horizontalMargin", mBadgeHorizontalMargin);

        // 徽章文本边缘与徽章背景边缘间的距离
        mBadgePadding = AttrUtil.getDimension(attr, "badge_padding", mBadgePadding);

        // 徽章在宿主控件中的位置
        String ordinal = AttrUtil.getStringValue(attr, "badge_gravity", "RightTop");
        mBadgeGravity = initAttrBadgeGravity(ordinal);

        // 是否可以拖拽删除徽章
        mDraggable = AttrUtil.getBooleanValue(attr, "badge_draggable", mDraggable);

        // 拖拽徽章超出轨迹范围后，再次放回到轨迹范围时，是否恢复轨迹
        mIsResumeTravel = AttrUtil.getBooleanValue(attr, "badge_isResumeTravel", mIsResumeTravel);

        // 徽章描边宽度
        mBadgeBorderWidth = AttrUtil.getDimension(attr, "badge_borderWidth", mBadgeBorderWidth);

        // 徽章描边颜色
        mBadgeBorderColor = AttrUtil.getColorInteger(attr, "badge_borderColor", "#ffffff");

        // 触发开始拖拽徽章事件的扩展触摸距离
        mDragExtra = AttrUtil.getDimension(attr, "badge_dragExtra", mDragExtra);
    }

    /**
     * 自定义属性位置获取
     *
     * @param gravityType String
     * @return Gravity
     */
    private BadgeGravity initAttrBadgeGravity(String gravityType) {
        if (gravityType.equalsIgnoreCase("RightTop")) {
            return BadgeGravity.RightTop;
        } else if (gravityType.equalsIgnoreCase("RightCenter")) {
            return BadgeGravity.RightCenter;
        } else if (gravityType.equalsIgnoreCase("RightBottom")) {
            return BadgeGravity.RightBottom;
        } else {
            return BadgeGravity.RightTop;
        }
    }

    /**
     * 默认设置画笔字体大小
     */
    private void afterInitDefaultAndCustomAttrs() {
        mBadgePaint.setTextSize(mBadgeTextSize);
    }

    /**
     * BgColor
     *
     * @param badgeBgColor int
     */
    public void setBadgeBgColorInt(int badgeBgColor) {
        mBadgeBgColor = badgeBgColor;
        mBadgeable.invalidate();
    }

    /**
     * TextColor
     *
     * @param badgeTextColor int
     */
    public void setBadgeTextColorInt(int badgeTextColor) {
        mBadgeTextColor = badgeTextColor;
        mBadgeable.invalidate();
    }

    /**
     * TextSize
     *
     * @param badgetextSize int
     */
    public void setBadgeTextSizeSp(int badgetextSize) {
        if (badgetextSize >= 0) {
            mBadgeTextSize = BGABadgeViewUtil.sp2px(mBadgeable.getContext(), badgetextSize);
            mBadgePaint.setTextSize(mBadgeTextSize);
            mBadgeable.invalidate();
        }
    }

    /**
     * VerticalMargin
     *
     * @param badgeVerticalMargin int
     */
    public void setBadgeVerticalMarginDp(int badgeVerticalMargin) {
        if (badgeVerticalMargin >= 0) {
            mBadgeVerticalMargin = BGABadgeViewUtil.dp2px(mBadgeable.getContext(), badgeVerticalMargin);
            mBadgeable.invalidate();
        }
    }

    /**
     * HorizontalMargin
     *
     * @param badgeHorizontalMargin int
     */
    public void setBadgeHorizontalMarginDp(int badgeHorizontalMargin) {
        if (badgeHorizontalMargin >= 0) {
            mBadgeHorizontalMargin = BGABadgeViewUtil.dp2px(mBadgeable.getContext(), badgeHorizontalMargin);
            mBadgeable.invalidate();
        }
    }

    /**
     * Padding
     *
     * @param badgePadding int
     */
    public void setBadgePaddingDp(int badgePadding) {
        if (badgePadding >= 0) {
            mBadgePadding = BGABadgeViewUtil.dp2px(mBadgeable.getContext(), badgePadding);
            mBadgeable.invalidate();
        }
    }

    /**
     * Gravity
     *
     * @param badgeGravity BadgeGravity
     */
    public void setBadgeGravity(BadgeGravity badgeGravity) {
        if (badgeGravity != null) {
            mBadgeGravity = badgeGravity;
            mBadgeable.invalidate();
        }
    }

    /**
     * Draggable
     *
     * @param draggable boolean
     */
    public void setDraggable(boolean draggable) {
        mDraggable = draggable;
        mBadgeable.invalidate();
    }

    /**
     * 拖拽徽章超出轨迹范围后，再次放回到轨迹范围时，是否恢复轨迹
     *
     * @param isResumeTravel boolean
     */
    public void setIsResumeTravel(boolean isResumeTravel) {
        mIsResumeTravel = isResumeTravel;
        mBadgeable.invalidate();
    }

    /**
     * BorderWidth
     *
     * @param badgeBorderWidthDp int
     */
    public void setBadgeBorderWidthDp(int badgeBorderWidthDp) {
        if (badgeBorderWidthDp >= 0) {
            mBadgeBorderWidth = BGABadgeViewUtil.dp2px(mBadgeable.getContext(), badgeBorderWidthDp);
            mBadgeable.invalidate();
        }
    }

    /**
     * BorderColor
     *
     * @param badgeBorderColor int
     */
    public void setBadgeBorderColorInt(int badgeBorderColor) {
        mBadgeBorderColor = badgeBorderColor;
        mBadgeable.invalidate();
    }

    /**
     * TouchEvent
     *
     * @param event TouchEvent
     * @return 事件处理
     */
    public boolean onTouchEventHelper(TouchEvent event) {
        switch (event.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                mBadgeDragExtraRectF.left =(float) NumberUtil.sub(mBadgeRectF.left,mDragExtra);
                mBadgeDragExtraRectF.top = (float) NumberUtil.sub(mBadgeRectF.top,mDragExtra);
                mBadgeDragExtraRectF.right = (float) NumberUtil.add(mBadgeRectF.right,mDragExtra);
                mBadgeDragExtraRectF.bottom = (float) NumberUtil.add(mBadgeRectF.bottom,mDragExtra);

                if ((mBadgeBorderWidth == 0 || mIsShowDrawable) && mDraggable && mIsShowBadge) {
                    mIsDragging = true;
                    MmiPoint point = event.getPointerPosition(event.getIndex());

                    if (mBadgeRectF.left <= point.getX() && mBadgeRectF.right >= point.getX()
                            && mBadgeRectF.top <= point.getY() && mBadgeRectF.bottom >= point.getY()) {
                        int[] badgeableRect = mBadgeable.getComponentRect().getLocationOnScreen();
                        int top = badgeableRect[1] - TOPTITLEHEIGHT;

                        double rectWidth = NumberUtil.div(mBadgeRectF.getWidth(),2);
                        double rectHeight = NumberUtil.div(mBadgeRectF.getHeight() , 2);

                        double mX = NumberUtil.add(mBadgeRectF.left,rectWidth);
                        double mY = NumberUtil.add(mBadgeRectF.top,rectHeight);

                        mDropBadgeView.setStickCenter((float) NumberUtil.add(badgeableRect[0],mX),(float) NumberUtil.add( top , mY));

                        mDropBadgeView.onTouchEvent(mDropBadgeView, event);
                        mBadgeable.invalidate();
                        return true;
                    }
                }
                return false;
            case TouchEvent.POINT_MOVE:
                if (mIsDragging) {
                    mDropBadgeView.onTouchEvent(mDropBadgeView, event);
                    return true;
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
            case TouchEvent.CANCEL:
                if (mIsDragging) {
                    mDropBadgeView.onTouchEvent(mDropBadgeView, event);
                    mIsDragging = false;
                    return true;
                }
                break;
            default:
                break;
        }
        return mBadgeable.callSuperOnTouchEvent(event);
    }

    /**
     * WithDismiss
     */
    public void endDragWithDismiss() {
        hiddenBadge();
        if (mDelegate != null) {
            mDelegate.onDismiss(mBadgeable);
        }
    }

    /**
     * DragWithout invalidate
     */
    public void endDragWithoutDismiss() {
        mBadgeable.invalidate();
    }

    /**
     * 画徽章
     *
     * @param canvas Canvas
     */
    public void drawBadge(Canvas canvas) {
        if (mIsShowBadge && !mIsDragging) {
            if (mIsShowDrawable) {
                LogUtil.error("drawBadge", "绘制图形徽章");
                drawDrawableBadge(canvas);
            } else {
                LogUtil.error("drawBadge", "绘制文字徽章");
                drawTextBadge(canvas);
            }
        }
    }

    /**
     * 绘制图像徽章
     *
     * @param canvas
     */
    private void drawDrawableBadge(Canvas canvas) {
        mBadgeRectF.left = mBadgeable.getWidth() - mBadgeHorizontalMargin - mBitmap.getImageInfo().size.width;
        mBadgeRectF.top = mBadgeVerticalMargin;
        switch (mBadgeGravity) {
            case RightTop:
                mBadgeRectF.top = mBadgeVerticalMargin;
                break;
            case RightCenter:
                double topSub = NumberUtil.sub(mBadgeable.getHeight() , mBitmap.getImageInfo().size.height);
                mBadgeRectF.top = (float) NumberUtil.div(topSub , 2);
                break;
            case RightBottom:
                mBadgeRectF.top = mBadgeable.getHeight() - mBitmap.getImageInfo().size.height - mBadgeVerticalMargin;
                break;
            default:
                break;
        }
        PixelMapHolder holder = new PixelMapHolder(mBitmap);
        canvas.drawPixelMapHolder(holder, mBadgeRectF.left, mBadgeRectF.top, mBadgePaint);
        mBadgeRectF.right =(float) NumberUtil.add( mBadgeRectF.left , mBitmap.getImageInfo().size.width);
        mBadgeRectF.bottom = (float) NumberUtil.add(mBadgeRectF.top , mBitmap.getImageInfo().size.height);
    }

    /**
     * 绘制文字徽章
     *
     * @param canvas
     */
    private void drawTextBadge(Canvas canvas) {
        String badgeText = "";
        if (!TextUtils.isEmpty(mBadgeText)) {
            badgeText = mBadgeText;
        }

        // 获取文本宽所占宽高
        mBadgeNumberRect = mBadgePaint.getTextBounds(badgeText);

        // 计算徽章背景的宽高
        int badgeHeight = mBadgeNumberRect.getHeight() + mBadgePadding * 2;
        int badgeWidth;

        // 当mBadgeText的长度为1或0时，计算出来的高度会比宽度大，此时设置宽度等于高度
        if (badgeText.length() == 1 || badgeText.length() == 0) {
            badgeWidth = badgeHeight;
        } else {
            badgeWidth = mBadgeNumberRect.getWidth() + mBadgePadding * 2;
        }

        // 计算徽章背景上下的值
        mBadgeRectF.top = mBadgeVerticalMargin;
        mBadgeRectF.bottom = mBadgeable.getHeight() - mBadgeVerticalMargin;
        switch (mBadgeGravity) {
            case RightTop:
                mBadgeRectF.bottom = (float) NumberUtil.add(mBadgeRectF.top , badgeHeight);
                break;
            case RightCenter:
                double topSub = NumberUtil.sub(mBadgeable.getHeight() , badgeHeight);
                mBadgeRectF.top = (float) NumberUtil.div(topSub , 2);
                mBadgeRectF.bottom = (float) NumberUtil.add(mBadgeRectF.top , badgeHeight);
                break;
            case RightBottom:
                mBadgeRectF.top = (float) NumberUtil.sub(mBadgeRectF.bottom , badgeHeight);
                break;
            default:
                break;
        }

        // 计算徽章背景左右的值
        mBadgeRectF.right = mBadgeable.getWidth() - mBadgeHorizontalMargin;
        mBadgeRectF.left = (float) NumberUtil.sub(mBadgeRectF.right , badgeWidth);

        if (mBadgeBorderWidth > 0) {

            // 设置徽章边框景色
            mBadgePaint.setColor(new Color(mBadgeBorderColor));

            // 绘制徽章边框背景
            canvas.drawRoundRect(mBadgeRectF,
                    (float) NumberUtil.div(badgeHeight , 2),
                    (float) NumberUtil.div(badgeHeight , 2),
                    mBadgePaint);

            // 设置徽章背景色
            mBadgePaint.setColor(new Color(mBadgeBgColor));

            // 绘制徽章背景
            double radiusXYmul = NumberUtil.mul(2,mBadgeBorderWidth);
            double radiusXYsub = NumberUtil.sub(badgeHeight,radiusXYmul);

            canvas.drawRoundRect(new RectFloat(
                    (float) NumberUtil.add(mBadgeRectF.left , mBadgeBorderWidth),
                    (float) NumberUtil.add(mBadgeRectF.top , mBadgeBorderWidth),
                    (float) NumberUtil.sub(mBadgeRectF.right , mBadgeBorderWidth),
                    (float) NumberUtil.sub(mBadgeRectF.bottom , mBadgeBorderWidth)),
                    (float) NumberUtil.div(radiusXYsub,2),
                    (float) NumberUtil.div(radiusXYsub,2), mBadgePaint);
            LogUtil.error("drawTextBadge", "绘制文本徽章");
        } else {
            // 设置徽章背景色
            mBadgePaint.setColor(new Color(mBadgeBgColor));

            // 绘制徽章背景
            canvas.drawRoundRect(mBadgeRectF, (float) NumberUtil.div(badgeHeight , 2), (float) NumberUtil.div(badgeHeight , 2), mBadgePaint);
            LogUtil.error("drawTextBadge", "绘制文本徽章 else");
        }


        if (!TextUtils.isEmpty(mBadgeText)) {

            // 设置徽章文本颜色
            mBadgePaint.setColor(new Color(mBadgeTextColor));

            // initDefaultAttrs方法中设置了mBadgeText居中，此处的x为徽章背景的中心点y
            double xdiv =  NumberUtil.div(badgeWidth , 2);
            float x = (float) NumberUtil.add(mBadgeRectF.left , xdiv);

            // 注意：绘制文本时的y是指文本底部，而不是文本的中间
            float y = (float) NumberUtil.sub(mBadgeRectF.bottom , mBadgePadding);

            // 绘制徽章文本
            canvas.drawText(mBadgePaint, badgeText, x, y);
        }
    }

    /**
     * showCirclePointBadge
     */
    public void showCirclePointBadge() {
        showTextBadge(null);
    }

    /**
     * showTextBadge
     *
     * @param badgeText String
     */
    public void showTextBadge(String badgeText) {
        mIsShowDrawable = false;
        mBadgeText = badgeText;
        mIsShowBadge = true;
        mBadgeable.invalidate();
    }

    /**
     * hiddenBadge
     */
    public void hiddenBadge() {
        mIsShowBadge = false;
        mBadgeable.invalidate();
    }

    /**
     * isShowBadge
     *
     * @return boolean
     */
    public boolean isShowBadge() {
        return mIsShowBadge;
    }

    /**
     * showDrawable
     *
     * @param bitmap PixelMap
     */
    public void showDrawable(PixelMap bitmap) {
        mBitmap = bitmap;
        mIsShowDrawable = true;
        mIsShowBadge = true;
        mBadgeable.invalidate();
    }

    /**
     * isShowDrawable
     *
     * @return boolean
     */
    public boolean isShowDrawable() {
        return mIsShowDrawable;
    }

    /**
     * getBadgeRectF
     *
     * @return RectFloat
     */
    public RectFloat getBadgeRectF() {
        return mBadgeRectF;
    }

    /**
     * BadgePadding
     *
     * @return int
     */
    public int getBadgePadding() {
        return mBadgePadding;
    }

    /**
     * BadgeText
     *
     * @return String
     */
    public String getBadgeText() {
        return mBadgeText;
    }

    /**
     * BadgeBgColor
     *
     * @return int
     */
    public int getBadgeBgColor() {
        return mBadgeBgColor;
    }

    /**
     * BadgeTextColor
     *
     * @return int
     */
    public int getBadgeTextColor() {
        return mBadgeTextColor;
    }

    /**
     * BadgeTextSize
     *
     * @return int
     */
    public int getBadgeTextSize() {
        return mBadgeTextSize;
    }

    /**
     * Bitmap
     *
     * @return PixelMap
     */
    public PixelMap getBitmap() {
        return mBitmap;
    }

    /**
     * DragDismissDelegate
     *
     * @param delegate BGADragDismissDelegate
     */
    public void setDragDismissDelegate(BGADragDismissDelegate delegate) {
        mDelegate = delegate;
    }

    /**
     * isResumeTravel
     *
     * @return boolean
     */
    public boolean isResumeTravel() {
        return mIsResumeTravel;
    }

    /**
     * isDragging
     *
     * @return boolean
     */
    public boolean isDragging() {
        return mIsDragging;
    }

    /**
     * isDraggable
     *
     * @return boolean
     */
    public boolean isDraggable() {
        return mDraggable;
    }

    /**
     * enum Gravity
     */
    public enum BadgeGravity {
        RightTop,
        RightCenter,
        RightBottom
    }

    /**
     * 传递顶层的View
     *
     * @param topComponent
     */
    public void setComponent(Component topComponent) {
        this.topComponent = topComponent;
        mDropBadgeView.setComponent(this.topComponent);
        TOPTITLEHEIGHT = topComponent.getLocationOnScreen()[1];
    }

    /**
     * 传递Canvas
     *
     * @param canvas
     */
    public void setMDrawTask(Canvas canvas) {
        mDropBadgeView.setMDrawTask(canvas);
    }
}
